//
//  WebViewAPI.swift
//  
//
//  Created by 孙长坦 on 2022/4/22.
//

import Foundation
import UIKit
import Moya
import LibBase
import LibNetwork

enum WebViewAPI {
    case request(baseUrl: String?,
                 url: String,
                 method: String?,
                 headers: [String: String]?,
                 params: [String: Any]?,
                 data: Any?)
    
    case download(url: URL, fileName: String?)
}

extension WebViewAPI: APITargetType {
    var baseURL: URL {
        switch self {
        case .request(let baseUrl, let url, _, _, _, _):
            guard let baseUrl = baseUrl else {
                return URL(string: url.ex.absoluteApiUrl)!
            }
            
            return URL(string: baseUrl)!
            
        case .download(let url, _):
            return url
        }
    }
    
    var path: String {
        switch self {
        case .request(let baseURL, let url, _, _, _, _):
            guard baseURL != nil else {
                return ""
            }
            return url
            
        case .download:
            return ""
        }
    }
    
    public var customizeHeaders: [String: String]? {
        switch self {
        case .request(_, _, _, let headers, _, _):
            guard let contentType = contentType else {
                return headers
            }
            
            return Dictionary.merging(value1: headers, value2: ["Content-Type": contentType])
            
        case .download:
            return nil
        }
    }
    
    var contentType: String? {
        switch self {
        case .request(_, _, _, _, _, let data):
            if data is [[String: Any]] {
                return nil
            } else if let dataMap = data as? [String: Any],
                      dataMap.contains(where: { _, value in
                          guard let value = value as? [String: Any],
                                let type = value["type"] as? String else {
                              return false
                          }
                          return ["file", "image"].contains(type)
                      }) {
                return nil
            } else if data != nil {
                return "application/json"
            }
            else {
                return nil
            }
            
        case .download(_, _):
            return nil
        }
    }
    
    var task: Task {
        switch self {
        case .request(_, _, _, _, let params, let data):
            if let dataList = data as? [[String: Any]] {
                return formData(data: dataList, params: params)
            } else if let dataMap = data as? [String: Any],
                      dataMap.contains(where: { _, value in
                          guard let value = value as? [String: Any],
                                let type = value["type"] as? String else {
                              return false
                          }
                          return ["file", "image"].contains(type)
                      }) {
                let dataList = dataMap.map { ["key": $0.key, "value": $0.value] }
                return formData(data: dataList, params:params)
            } else if let data = data, let jsonData = try? JSONSerialization.data(withJSONObject: data) {
                if let params = params {
                    return .requestCompositeData(bodyData: jsonData,
                                                 urlParameters: params)
                } else {
                    return .requestData(jsonData)
                }
            }
            else if let params = params, params.count > 0 {
                return .requestParameters(parameters: params,
                                          encoding: URLEncoding.queryString)
            } else {
                return .requestPlain
            }
            
        case .download(let url, let fileName):
            return .downloadDestination { temporaryURL, response in
                return (url.ex.downloadLocation(fileName: fileName),
                        [.createIntermediateDirectories, .removePreviousFile])
            }
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .request(_, _, let method, _, _, _):
            return Moya.Method(rawValue: method?.uppercased() ?? "GET")
            
        case .download:
            return .get
        }
    }
    
    var sampleData: Data {
        switch self {
        case .request, .download:
            return Data()
        }
    }
    
    private func formData(data: [[String: Any]], params: [String: Any]?) -> Task {
        let formDatas: [MultipartFormData] = data.compactMap { element in
            guard let key = element["key"] as? String else {
                return nil
            }
            
            if let value = element["value"] as? String,
               let data = value.data(using: .utf8) {
                return MultipartFormData(provider: .data(data),
                                         name: key)
            } else if let value = element["value"] as? [String: Any],
                      let base64Str = value["data"] as? String,
                      let data = Data(base64Encoded: base64Str) {
                return MultipartFormData(provider: .data(data),
                                         name: key,
                                         fileName: value["fileName"] as? String,
                                         mimeType: value["mimeType"] as? String)
            } else {
                return nil
            }
        }
        
        if let params = params {
            return .uploadCompositeMultipart(formDatas, urlParameters: params)
        } else {
            return .uploadMultipart(formDatas)
        }
    }
}
